package project1;


import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class RequestThread extends Thread {
	private boolean dead;
	private DatagramSocket requestSocket;
	private ICommand comm;
	private String address;
	private int port;
	private TimeOutBehavior behavior;
	private int waitInterval;
	
	public RequestThread(ICommand comm, DatagramSocket requestSocket, String address, int port, TimeOutBehavior behavior, int waitInterval) {
		super();
		this.requestSocket = requestSocket;
		this.dead = false;
		this.comm = comm;
		this.address = address;
		this.port = port;
		this.behavior = behavior;
		this.waitInterval = waitInterval;
	}
	
	@Override
	public void run() {
		if (waitInterval != -1) {
			try {
				Thread.sleep(waitInterval * 1000);
			} catch (InterruptedException e) {
				System.out.println("[SYSTEM] Internal error. RequestThread waiting error. ");
			}
			
		}
		byte[] message = null;
		try {
			message = comm.generateMessage();
		} catch (Exception e) {
			System.out.println("[ERROR] Internal error when sending data to the server. ");
			MainRequestThread.decrementSeqNo();
			return;
		}
		
		for (int i = 0; i < MainClass.MAX_TIME_TRYING; i++) {
			if (!dead) {
				try {
					while (MainRequestThread.getNextSentSeqNum() < comm.getSeqNum()) {
						Thread.sleep(10);
					}
					requestSocket.send(new DatagramPacket(message, message.length, InetAddress.getByName(address), port));

					if (MainRequestThread.getNextSentSeqNum() == comm.getSeqNum()) {
						MainRequestThread.incrementNextSentSeqNum();
					}
				} catch (Exception e) {
					e.printStackTrace();
					if (requestSocket.isClosed()) {
						break;
					}
				}
			} else {
				break;
			}
			try {
				Thread.sleep(MainClass.TIME_INTERVAL);
			} catch (InterruptedException e) {
				System.out.println("Error when sleeping the thread. ");
				e.printStackTrace();
			}
		}
		if (!dead) {
			behavior.behave();
		}
	}
	
	public void close() {
		this.dead = true;
	}
	
	public ICommand getCommand() {
		return this.comm;
	}
}
